package ctu.kfad.run;

import ctu.kfad.run.iterpreter.Interpreter;
import ctu.kfad.run.memory.IStackObjectProvider;
import ctu.kfad.run.memory.MemoryManager;
import ctu.kfad.run.stack.AStackObject;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

public class SimpleJVM implements IStackObjectProvider {

    final String environment;
    final String mainClass;

    public static void main(String[] args) throws ClassNotFoundException {
//        final String environment = "target/classes";
//        final String mainClass = "executable.knapsack.Knapsack";
//        final String sourceFile = "files/knapsackTask";
//        final String destinationFile = "files/knapsackResult";

//        String[] args = new String[]{environment,mainClass,sourceFile};

        if (args.length < 2) {
            System.out.println("Exiting because of missing arguments: Required arguments are: 1 - classpath root , 2 - main class name ");
        }

        final SimpleJVM simpleJVM = new SimpleJVM(args[0], args[1]);
        simpleJVM.start(Arrays.copyOfRange(args, 2, args.length));
    }

    public SimpleJVM(String environment, String mainClass) {
        this.environment = environment;
        this.mainClass = mainClass;
    }

    public void start(String[] arguments) {
        ClassFileRepository repository = new ClassFileRepository(new File(environment));
        InstanceController instanceController = new InstanceController(repository, new MemoryManager());

        JavaClass clazz = repository.loadClass(mainClass);
        final Method method = findMethodByName("main", clazz);

        Stack<AStackObject> initStack = new Stack();
        initStack.push(instanceController.saveStringArray(arguments, this));

        final Interpreter interpreter = new Interpreter(null, instanceController, clazz, method, initStack);
        interpreter.interpret();
    }

    public static Method findMethodByName(String name, JavaClass clazz) {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (name.equals(method.getName())) {
                return method;
            }
        }
        throw new RuntimeException(String.format("Method with name '%s' doesn't exist", name));
    }

    @Override
    public List<AStackObject> getStackObjects() {
        return Collections.emptyList();
    }
}
